package com.example.database;

// Tao cau truc cua CSDL

//import java.lang.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.annotation.SuppressLint;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

@SuppressLint("UseValueOf")
public class myDBHelper extends SQLiteOpenHelper {
	// Tao co so du lieu
	public static final int DATABASE_VERSION = 1;
	public static final String DATABASE_NAME = "WifiModel";

	// Tao Table thong tin ve cac chi so trong Map_id
	public static final String TABLE_MAPInfor = "MapInformation";
	// tao colum trong bangx
	public static final String CREATE_TABLE_MAPInfor = "CREATE TABLE MapInformation("
			+ "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "
			+ "Name TEXT, "
			+ "x REAL NOT NULL, "
			+ "y REAL NOT NULL, "
			+ "width INTEGER NOT NULL, "
			+ "height INTEGER NOT NULL)";

	// Tao Table thong tin ve cac gia tri khoi tao
	public static final String TABLE_APLocation = "Connect_AP";
	// Tao colum luu cac gia tri lien quan den AP
	public static final String CREATE_TABLE_APLocation = "CREATE TABLE Connect_AP("
			+ "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
			+ "MapID INTEGER,"
			+ "APName TEXT NOT NULL,"
			+ "channel  INTEGER,"
			+ "freq  REAL,"
			+ "stand TEXT,"
			+ "ipServer TEXT,"
			+ "user INTEGER," 
			+ "xAP  REAL NOT NULL," 
			+ "yAP  REAL NOT NULL)";

	public static final String TABLE_SSIDCollect = "APPlanAndCollect";
	public static final String CREATE_TABLE_SSIDCollect = "CREATE TABLE APPlanAndCollect ("
			+ "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
			+ "APID INTEGER NOT NULL,"
			+ "D REAL NOT NULL,"
			+ "AG REAL NOT NULL,"
			+ "x REAL NOT NULL,"
			+ "y REAL NOT NULL,"
			+ "RSSI INTEGER ,"
			+ "BW REAL ,"
			+ "Interval REAL ,"
			+ "Transfer REAL ,"
			+ "VarMethod INTEGER ,"
			+ "VarEquip INTEGER ,"
			+ "TypeObs INTEGER ,"
			+ "InsideObs INTEGER ,"
			+ "OutsideObs  INTEGER ,"
			+ "CollectedDate DATETIME )";

	// Table chua cac gia tri noi suy
	public static final String TABLE_SSIDInf = "APGenInfo";
	public static final String CREATE_TABLE_SSIDInf = "CREATE TABLE APGenInfo("
			+ "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
			+ "APID INTEGER NOT NULL,"
			+ "x REAL NOT NULL,"
			+ "y REAL NOT NULL," 
			+ "D REAL NOT NULL," 
			+ "AG REAL NOT NULL,"
			+ "RSSI INTEGER NOT NULL,"
			+ "PowLevel INTEGER ," 
			+ "BW INTEGER NOT NULL,"
			+ "BandLevel INTEGER )";

	// Tao bang xu ly cac gia tri RSSI theo muc level
	public static final String TABLE_APLevel = "APLevel";
	public static final String CREATE_TABLE_APLevel = "CREATE TABLE APLevel ("
			+ "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
			+ "APID INTEGER NOT NULL," 
			+ "x REAL NOT NULL,"
			+ "y REAL NOT NULL,"
			+ "Level INTEGER NOT NULL)";

	public static final String TABLE_PolyOptions = "PolyOptions";
	public static final String CREATE_TABLE_PolyOptions = "CREATE TABLE PolyOptions ("
			+ "ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,"
			+ "Color TEXT, "
			+ "zIndex INTEGER)";

	public myDBHelper(Context context) {
		super(context, DATABASE_NAME, null, DATABASE_VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL(CREATE_TABLE_MAPInfor);
		db.execSQL(CREATE_TABLE_APLocation);
		db.execSQL(CREATE_TABLE_SSIDCollect);
		db.execSQL(CREATE_TABLE_SSIDInf);
		db.execSQL(CREATE_TABLE_APLevel);
		db.execSQL(CREATE_TABLE_PolyOptions);
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_MAPInfor);
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_APLocation);
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_SSIDCollect);
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_SSIDInf);
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_APLevel);
		db.execSQL("DROP TABLE IF EXISTS " + TABLE_PolyOptions);
		onCreate(db);
	}

	// ---------------------------------------------------------------------------------
	// Cac ham tuong tac co so du lieu voi bang TABLE_MAPInfor

	public void addMapInfor(String MapName, float x, float y, float width, float height) {
		SQLiteDatabase db = this.getWritableDatabase();

		ContentValues value = new ContentValues();
		value.put("Name", MapName);
		value.put("x", x);
		value.put("y", y);
		value.put("width", width);
		value.put("height", height);
		db.insert(TABLE_MAPInfor, null, value);
		db.close();
	}

	public int getMapId(String MapName) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select ID from " + TABLE_MAPInfor
				+ " where Name = " + MapName + " Order By ID desc limit 1 ", null);
		int IdIndex = c.getColumnIndex("ID");
		c.moveToFirst();
		int result = c.getInt(IdIndex);
		return result;
	}

	public String[] getMapsize(int MapId) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select width, height from " + TABLE_MAPInfor
				+ " where ID = " + MapId, null);
		String[] result = new String[2];
		c.moveToFirst();
		result[0] = c.getString(0);
		result[1] = c.getString(1);
		return result;
	}

	public String getMapname() {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select Name from " + TABLE_MAPInfor, null);
		c.moveToFirst();
		String result = c.getString(c.getColumnIndex("Name"));
		return result;
	}

	// -------------------------------------------

	// Cac ham tuong tac co so du lieu voi bang TABLE_APLocation

	public void addAPLocation(int MapId, String APName, float x, float y) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("MapID", MapId);
		value.put("APName", APName);
		value.put("xAP", x);
		value.put("yAP", y);
		db.insert(TABLE_APLocation, null, value);
		db.close();
	}

	public int MapId(int APID) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select MapID from " + TABLE_APLocation
				+ " where ID = " + APID + " Order By ID desc limit 1 ", null);
		int IdIndex = c.getColumnIndex("MapID");
		c.moveToFirst();
		int result = c.getInt(IdIndex);
		return result;
	}
	
	public List<String> getAPName(int mapId) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select ID, APName from " + TABLE_APLocation
				+ " Where MapID = '" + mapId + "'", null);
		List<String> name = new ArrayList<String>();
		c.moveToFirst();
		for (int n = 0; n < c.getCount(); n++) {
			String N = c.getString(0);
			String AP = c.getString(1);
			name.add(N + " " + AP);
			c.moveToNext();
		}
		db.close();
		return name;
	}

	public void updateAPPrams(int channel, float freq, String stand, String IP, int user, int APID) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("channel", channel);
		value.put("freq", freq);
		value.put("stand", stand);
		value.put("ipServer", IP);
		value.put("user", user);
		String where = "APID = '" + APID + "'";
		db.update(TABLE_APLocation, value, where, null);
		db.close();
	}
	
	public String getIP(int APID) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select ipServer from " + TABLE_APLocation
				+ " Where APID = '" + APID + "'", null);
		int IdIndex = c.getColumnIndex("ipServer");
		c.moveToFirst();
		String result = c.getString(IdIndex);
		return result;
	}

	public String[] getAPpos(int APID) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select xAP, yAP from " + TABLE_APLocation
				+ " where ID = " + APID, null);
		String[] result = new String[2];
		c.moveToFirst();
		result[0] = c.getString(0);
		result[1] = c.getString(1);
		return result;
	}

	// ---------------------------------------
	// Cac ham tuong tac co so du lieu voi bang TABLE_SSIDCollect

	public void addAPPlan(int APID, float radius, float angle, float x, float y) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("APID", APID);
		value.put("D", radius);
		value.put("AG", angle);
		value.put("x", x);
		value.put("y", y);
		db.insert(TABLE_SSIDCollect, null, value);
		db.close();
	}

	public int getPlanCount(int APID) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select COUNT(ID) from " + TABLE_SSIDCollect
				+ " where APID = " + APID, null);
		c.moveToFirst();
		int result = c.getInt(0);
		return result;
	}

	public int getPointId(int APID) {
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db
				.rawQuery("select ID from " + TABLE_SSIDCollect
						+ " where APID = " + APID
						+ " Order By ID desc limit 1 " + " GROUP By APID ", null);		
		c.moveToFirst();
		int IdIndex = c.getColumnIndex("ID");
		int result = c.getInt(IdIndex);
		return result;
	}
	
	public String[] getScanpos(int APID, int pos) {
		
		SQLiteDatabase db = this.getReadableDatabase();
		Cursor c = db.rawQuery("select  x , y  from "
				+ TABLE_SSIDCollect + " where APID = " + APID + " AND ID = " + pos + " ORDER By D", null);
		String[] result = new String[2];
		c.moveToFirst();
		result[0] = c.getString(0);
		result[1] = c.getString(1);
		return result;
	}

	
	
	public void insertBW(int AIPD, float interval, float transfer, float bw) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("Interval", interval);
		value.put("Transfer", transfer);
		value.put("BW", bw);
		String where = "AIPD = " + AIPD;
		db.insert(TABLE_SSIDCollect, where, value);
		db.close();
	}

	public void insertSignal(int AIPD, int rssi, int type, int inside, int outside) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("RSSI", rssi);
		value.put("TypeObs", type);
		value.put("InsideObs", inside);
		value.put("OutsideObs", outside);
		String where = "AIPD = " + AIPD;
		db.insert(TABLE_SSIDCollect, where, value);
		db.close();
	}

	public void addError(float VarM, float VarE) {
		SQLiteDatabase db = this.getWritableDatabase();

		ContentValues value = new ContentValues();
		value.put("VarMethod", VarM);
		value.put("VarEquip", VarE);
		db.insert(TABLE_SSIDCollect, null, value);
		db.close();
	}

	// Loc cac tap diem khởi tạo thành một mảng
		public List<Point> getPoint(int APID) {
			List<Point> list = new ArrayList<Point>();
			SQLiteDatabase db = this.getReadableDatabase();
			// Các cột giá trị của các bảng sẽ lấy
			String query = "select x, y from" + TABLE_SSIDCollect + " where APID = "
					+ APID ;
			
			Cursor c = db.rawQuery(query, null);
			c.moveToFirst();
			for (int i = 0; i < c.getCount(); i++) {
				float x = c.getColumnIndex("x");
				float y = c.getColumnIndex("y");
				Point point = new Point(x, y);
				list.add(point);
				c.moveToNext();
			}
			db.close();
			return list;
		}
		
		// Tính giá trị hệ số suy hao trong môi trường LOS
		public float n(int APID) {
			SQLiteDatabase db = this.getReadableDatabase();
			// Các cột giá trị của các bảng sẽ lấy
			String query = "select D, RSSI from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " AND TypeObs = 0 ORDER By D";
			Cursor cv = db.rawQuery(query, null);

			float d0 = 0;// khoảng cách đo đầu tiên cách 1m -> 5m dùng làm chỉ số tham chiếu
			float Prx0 = 0;// chỉ số RSSI thu được tại khoảng cách trên
			cv.moveToFirst();
			d0 = Float.parseFloat(cv.getString(0));
			Prx0 = Float.parseFloat(cv.getString(1));
			
			
			float sub = 0; // (A - Prxi)
			float div = 0; // 10log(d/d0)
			float total = 0; // nLOS
			if (cv.getCount() == 1) {
				sub += (Prx0) * 10 * (Math.log(d0));
				div += (10 * Math.log((d0) * (d0)));
			} else {
				cv.moveToNext();
				float d = 0;// khoảng cách thu đo tại vị trí khác d0
				float Prxd = 0;// chỉ số RSSI thu được tại vị trí khác d0
				for (int i = 2; i < cv.getCount(); i++) {
					d = Float.parseFloat(cv.getString(0));
					Prxd = Float.parseFloat(cv.getString(1));
					sub += (Prx0 - Prxd) * 10 * (Math.log(d / d0));
					div += Math.pow((10 * (Math.log(d / d0))), 2);
					cv.moveToNext();
				}
			}
			total = sub / div;
			cv.close();
			return total;
		}

		// Tính độ lệch chuẩn của các giá trị ước lượng với các giá trị đã đo cua LOS
		public float StandDiv(int APID) {
			SQLiteDatabase db = this.getReadableDatabase();
			String query1 = "select D, RSSI from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " AND TypeObs = 0"
					+ " ORDER By D";
			Cursor c1 = db.rawQuery(query1, null);
			float d0 = 0f;
			float RSSI0 = 0f; // Giá trị đo được tại vị trí d0
			float d = 0f;
			float RSSI = 0f; // Giá trị đo được tại vị trí d
			float RSSInew = 0f;// Giá trị sẽ nội suy tại vị trí d
			float sub = 0;
			float total = 0;
			float n = n(APID);
			c1.moveToFirst();
			d0 = Float.parseFloat(c1.getString(0));
			RSSI0 = Float.parseFloat(c1.getString(1));
			c1.moveToNext();
			for (int i = 1; i <= c1.getCount(); i++) {
				d = Float.parseFloat(c1.getString(0));
				RSSI = Float.parseFloat(c1.getString(1));
				RSSInew = (float) (RSSI0 - 10*n*Math.log(d/d0));
				sub += RSSInew - RSSI;
				c1.moveToNext();
			}
			total = (float) (sub / Math.sqrt(c1.getCount()));
			c1.close();
			return total;
		}
		
		// Match các giá trị RSSI tương ứng với các mức màu khác nhau
		public int LevelRSSI(float RSSI) {
			int level;
			if (RSSI >= -25 & RSSI <= -20) {// giới hạn ngưỡng thu của
				// thiết bị còn tìm thấy sóng
				level = 1;
			} else if (RSSI >= -30 & RSSI < -25) {
				level = 2;
			} else if (RSSI >= -35 & RSSI < -30) {
				level = 3;
			} else if (RSSI >= -40 & RSSI < -45) {
				level = 4;
			} else if (RSSI >= -45 & RSSI < -50) {
				level = 5;
			} else if (RSSI >= -50 & RSSI < -45) {
				level = 6;
			} else if (RSSI >= -55 & RSSI < -50) {
				level = 7;
			} else if (RSSI >= -60 & RSSI < -55) {
				level = 8;
			} else if (RSSI >= -65 & RSSI < -60) {
				level = 9;
			} else if (RSSI >= -70 & RSSI < -65) {
				level = 10;
			} else if (RSSI >= -75 & RSSI < -70) {
				level = 11;
			} else if (RSSI >= -80 & RSSI < -75) {
				level = 12;
			} else if (RSSI >= -85 & RSSI < -80) {
				level = 13;
			} else if (RSSI >= -90 & RSSI < -85) {
				level = 14;
			} else
				level = 15;
			return level;
		}
		
		// Uoc luong tat ca cac diem xoay 360 độ quanh Access Point
		// Lấy giá trị biên của từng level
		public void RSSILOS(int APID) {
			SQLiteDatabase db = this.getReadableDatabase();
			String query = "select D, AG, RSSI  from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " ORDER By D";
			Cursor c = db.rawQuery(query, null);

			float DGen = 0f;// khoang cach do tai vi tri D noi suy
			float RSSIGen = 0f;// chỉ số RSSI se noi suy vị trí D
			int AGGen = 0; // Góc của điểm noi suy so với trục toạ độ đecac
			float x = 0f;
			float y = 0f;
			float RSSI0 = 0f;
			float D0 = 0f;
			int limit = -92;// giới hạn ngưỡng thu của thiết bị còn tìm thấy sóng
			int level;
			float n = n(APID);
			float error = StandDiv(APID);
			String[] apname = this.getAPpos(APID); // lấy vị trí toạ độ AP
			float xtemp = Float.parseFloat(apname[0]);
			float ytemp = Float.parseFloat(apname[1]);
			
			// lấy chỉ số tín hiệu RSSI0 tại khoảng đo đầu tiên
			c.moveToFirst();
			D0 = Float.parseFloat(c.getString(0));
			RSSI0 = Float.parseFloat(c.getString(2));
			//
			c.moveToNext();
			int i = 0;
			for (AGGen = 0; AGGen <= 360; AGGen++) {// cho goc xoay quanh AP
				DGen = D0 + 1;// gán tất cả các điểm có bán kính bằng D
				Log.d("first_loop", AGGen + "");
				do {
					// Ứng với mỗi góc, tại bán kính D có được giá trị tín hiệu nội suy
					float log = (float) Math.log(DGen / D0);
					double log2 = Math.log(DGen / D0);
					float v2 = 10 * n * log;
					RSSIGen = (float) (RSSI0 - v2) + error;
					level = LevelRSSI(RSSIGen);
					
					// Xac dinh toa do cho diem co khoang cach noi suy
					x = (float) (DGen * Math.cos(AGGen) * 180 / Math.PI);
					y = (float) (DGen * Math.sin(AGGen) * 180 / Math.PI);
					// Doi he truc toa do
					xtemp = xtemp + x;
					ytemp = ytemp + y;
					
					// Chèn dữ liệu vừa nội suy vao bảng TABLE_SSIDInf
					ContentValues vl = new ContentValues();
					vl.put("APID", APID);
					vl.put("D", DGen);
					vl.put("AG", AGGen);
					vl.put("RSSI", RSSIGen);
					vl.put("x", xtemp);
					vl.put("y", ytemp);
					vl.put("PowLevel", level);
					vl.put("TypeObs", 0);
					vl.put("BW", 0);
					DGen += 1;
					db.insert(TABLE_SSIDInf, null, vl);
					
					Log.d("order", (i = i + 1) + "");
					Log.d("Dgen/D0_" + i, DGen / D0 + "");
					Log.d("Log_" + i, log + "");
					Log.d("Log2_" + i, log2 + "");
					Log.d("v2_" + i, v2 + "");
					Log.d("check", RSSIGen + ", " + limit);
				} while (RSSIGen > limit);
			}
			db.close();
		}
		
		// Tính hệ số suy hao trong môi trường NLOS
		public float nObs(int APID, int k) {
			SQLiteDatabase db = this.getReadableDatabase();
			String query = "select MIN(ID) from " + TABLE_SSIDCollect
					+ " where APID = " + APID;
			Cursor c = db.rawQuery(query, null);
			c.moveToFirst();
			int minID = c.getInt(0);
			c.close();

			String query1 = "select D, RSSI from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " AND ID = " + minID + " ORDER By D";
			Cursor c1 = db.rawQuery(query1, null);
			float d0 = 0;// khoảng cách đo đầu tiên cách 1m -> 5m dùnglàm chỉ số tham chiếu
			float Prx0 = 0;// chỉ số RSSI thu được tại khoảng cách trên
			c1.moveToFirst();
			d0 = Float.parseFloat(c1.getString(0));
			Prx0 = Float.parseFloat(c1.getString(1));
			c1.close();

			String query2 = "select D, RSSI from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " AND TypeObs = " + k
					+ " AND OutsideObs != " + "" + " ORDER By D";
			Cursor c2 = db.rawQuery(query2, null);
			float d = 0;// khoảng cách thu đo tại vị trí khác d0
			float Prxd = 0;// chỉ số RSSI thu được tại vị trí khác d0
			float sub = 0;
			float div = 0;
			
			c2.moveToFirst();
			for (int i = 0; i < c2.getCount(); i++) {
				d = Float.parseFloat(c2.getString(0));
				Prxd = Float.parseFloat(c2.getString(1));
				sub += (Prx0 - Prxd) * 10 * (Math.log(d / d0));
				div += Math.pow((10 * Math.log((d/d0) *(d/d0))),2);
				c2.moveToNext();
			}
			sub = sub / div;
			c2.close();
			return sub;
		}

		// Tính độ lệch chuẩn của các giá trị ước lượng với các giá trị đã đo cua NLOS
		public float StandDivNlos(int APID, int k) {
			SQLiteDatabase db = this.getReadableDatabase();
			String query = "select MIN(ID) from " + TABLE_SSIDCollect
					+ " where APID = " + APID;
			Cursor c = db.rawQuery(query, null);
			c.moveToFirst();
			int minID = c.getInt(0);
			c.close();

			String query1 = "select D, RSSI from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " AND ID = " + minID + " ORDER By D";
			Cursor c1 = db.rawQuery(query1, null);
			float d0 = 0;// khoảng cách đo đầu tiên cách 1m -> 5m dùnglàm chỉ số tham chiếu
			float RSSI0 = 0f; // Giá trị đo được tại vị trí d0
			c1.moveToFirst();
			d0 = Float.parseFloat(c1.getString(0));
			RSSI0 = Float.parseFloat(c1.getString(1));
			c1.close();
			
			String query2 = "select D, RSSI from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " AND TypeObs = " + k
					+ " AND OutsideObs != " + "" + " ORDER By D";
			Cursor c2 = db.rawQuery(query2, null);
			float d = 0f;
			float RSSI = 0f; // Giá trị đo được tại vị trí d
			float RSSInew = 0f;// Giá trị sẽ nội suy tại vị trí d
			float sub = 0;
			float total = 0;
			float n = n(APID);
			c2.moveToFirst();
			for (int i = 0; i < c2.getCount(); i++) {
				d = Float.parseFloat(c2.getString(0));
				RSSI = Float.parseFloat(c2.getString(1));
				RSSInew = (float) (RSSI0 - 10*n*Math.log(d/d0));
				sub += RSSInew - RSSI;
				c2.moveToNext();
			}
			total = (float) (sub / Math.sqrt(c2.getCount()));
			c2.close();
			return total;
		}
		
		// Uoc luong lai cac diem NLOS được giới hạn là góc biên từ vị trí
		// bắt đầu vật cản đến kết thúc vật cản

		// Phuong trinh doan chắn giữa hai điểm đo phía sau vật cản
	public int xy(float x, float y, float x1, float y1, float x2, float y2) {

		if ((x - x2) / (x2 - x1) == (y - y1) / (y - y2)) {
			return 1;
		} else
			return 0;
	}
	
	// Xet cac diem thuoc ranh gioi tu InsideObs tro di
	public int xyinside(int APID, int k, float x, float y) {
		SQLiteDatabase db = this.getReadableDatabase();
		String query1 = "select x, y from " + TABLE_SSIDCollect
				+ " where APID = " + APID + " AND TypeObs = " + k
				+ " AND InsideObs != " + "" + " ORDER By InsideObs";
		Cursor c1 = db.rawQuery(query1, null);
		int result = 0;
		c1.moveToFirst();
		for (int i = 2; i < c1.getCount(); i++) {
			c1.moveToNext();
			float x1 = c1.getInt(0);
			float y1 = c1.getInt(1);
			c1.moveToNext();
			float x2 = c1.getInt(0);
			float y2 = c1.getInt(1);
			if (xy(x, y, x1, y1, x2, y2) == 1) {
				result = 1;
			} else
				result = 0;
		}
		return result;
	}

	// Xet cac diem thuoc ranh gioi tu Outside tro di
	public int xyoutside(int APID, int k, float x, float y) {
		SQLiteDatabase db = this.getReadableDatabase();
		String query1 = "select x, y from " + TABLE_SSIDCollect
				+ " where APID = " + APID + " AND TypeObs = " + k
				+ " AND OutsideObs != " + "" + " ORDER By OutsideObs";
		Cursor c1 = db.rawQuery(query1, null);
		int result = 0;
		c1.moveToFirst();
		for (int i = 2; i < c1.getCount(); i++) {
			c1.moveToNext();
			float x1 = c1.getInt(0);
			float y1 = c1.getInt(1);
			c1.moveToNext();
			float x2 = c1.getInt(0);
			float y2 = c1.getInt(1);
			if (xy(x, y, x1, y1, x2, y2) == 1) {
				result = 1;
			} else
				result = 0;
		}
		return result;
	}
	
	// Tìm độ dày của vật chắn tính từ AP
	public float DMaxObs(int APID, int k) {
		SQLiteDatabase db = this.getReadableDatabase();
		String query1 = "select MAX(D) from " + TABLE_SSIDCollect
				+ " where APID = " + APID + " AND TypeObs = " + k
				+ " AND InsideObs !=" + "";
		Cursor c1 = db.rawQuery(query1, null);
		String query2 = "select MAX(D) from " + TABLE_SSIDCollect
				+ " where APID = " + APID + " AND TypeObs = " + k
				+ " AND OutsideObs !=" + "";
		Cursor c2 = db.rawQuery(query2, null);
		float result = 0;
		c1.moveToFirst();
		c2.moveToFirst();
		result = Float.parseFloat(c2.getString(0))
				- Float.parseFloat(c1.getString(0));
		return result;
	}
	
	// Dem số vat can có trong thực địa
		public int numObs(int APID) {
			SQLiteDatabase db = this.getReadableDatabase();
			String query = "select TypeObs, MIN(D) from " + TABLE_SSIDCollect
					+ " where APID = " + APID + " GROUP By TypeObs";
			Cursor c = db.rawQuery(query, null);
			int count = 1;
			for (c.moveToFirst(); !c.isLast(); c.moveToNext()) {
				if (Integer.parseInt(c.getString(0)) != 0) {
					count = count + 1;
				}
			}
			return count;
		}

	public void RSSINLOS(int APID, int k) {
		SQLiteDatabase db = this.getReadableDatabase();
		int level;
		int limit = -92;
		float DGen = 0f;
		float RSSIGen = 0f;
		float AGGen = 0f;
		float del = 0f;
		float n = nObs(APID, k);
		float error = StandDivNlos(APID, k);

		// Lấy giá trị đo tại vị trí đầu tiên làm tham chiếu
		String query = "select MIN(ID) from " + TABLE_SSIDCollect
				+ " where APID = " + APID;
		Cursor c = db.rawQuery(query, null);
		c.moveToFirst();
		int minID = c.getInt(0);
		c.close();
		String query0 = "select D, RSSI from " + TABLE_SSIDCollect
				+ " where APID = " + APID + " AND ID = " + minID + " ORDER By D";
		Cursor c0 = db.rawQuery(query0, null);
		c0.moveToFirst();
		float D0 = Float.parseFloat(c0.getString(0));
		float RSSI0 = Float.parseFloat(c0.getString(1));
		c0.close();

		// Tìm các điểm có TypeObs !=0 trong dữ liệu đo
		// Lấy các giá trị biên của vật chắn
		String query1 = "select InsideObs, D, AG, x, y from "
				+ TABLE_SSIDCollect + " where APID = " + APID + " AND TypeObs = "
				+ k + " AND InsideObs IS NOT NULL "  + " ORDER By InsideObs";
		Cursor c1 = db.rawQuery(query1, null);
		c1.moveToFirst();
		float dminIn = c1.getInt(1);
		float agminIn = c1.getInt(2);
		float xminIn = c1.getInt(3);
		float yminIn = c1.getInt(4);
		c1.moveToLast();
		float dmaxIn = c1.getInt(1);
		float agmaxIn = c1.getInt(2);
		float xmaxIn = c1.getInt(3);
		float ymaxIn = c1.getInt(4);

		String query2 = "select OutsideObs, D, AG, x, y from "
				+ TABLE_SSIDCollect + " where APID = " + APID + " AND TypeObs = "
				+ k + " AND OutsideObs IS NOT NULL "  + " ORDER By OutsideObs";
		Cursor c2 = db.rawQuery(query2, null);
		c2.moveToFirst();
		float dminOut = c2.getInt(1);
		float agminOut = c2.getInt(2);
		float xminOut = c2.getInt(3);
		float yminOut = c2.getInt(4);
		c2.moveToLast();
		float dmaxOut = c2.getInt(1);
		float agmaxOut = c2.getInt(2);
		float xmaxOut = c2.getInt(3);
		float ymaxOut = c2.getInt(4);
//					
//					String query6 = "select * from " + TABLE_SSIDInf;
//					Cursor cTemp = db.rawQuery(query6, null);
//
		Cursor c5 =null;
		if ((agminIn <= agminOut) & (agmaxIn <= agmaxOut)) {
			String key1 = " AG >=" + agminIn;
			String key2 = " AG <=" + agmaxIn;
			String query5 = "select x, y, RSSI, D, AG from " + TABLE_SSIDInf
					+ " where APID = " + APID + " AND " + key1 + " AND " + key2
					+ " AND D >= " + dminIn + " AND D <= " + dminOut
					+ " ORDER By AG";
			c5 = db.rawQuery(query5, null);
			del = Math.abs(agminOut - agmaxOut);
		} else if ((agminIn >= agminOut) & (agmaxIn >= agmaxOut)) {
			String key1 = " AG >=" + agminOut;
			String key2 = " AG <=" + agmaxOut;
			String query5 = "select x, y, RSSI, D, AG from " + TABLE_SSIDInf
					+ " where APID = " + APID + " AND " + key1 + " AND " + key2
					+ " AND D >= " + dminIn + " AND D <= " + dminOut
					+ " ORDER By AG";
			c5 = db.rawQuery(query5, null);
			del = Math.abs(agminIn - agmaxIn);
		} else if ((agminIn <= agminOut) & (agmaxIn <= agmaxOut)) {
			String key1 = " AG >=" + agminOut;
			String key2 = " AG <=" + agminOut;
			String query5 = "select x, y, RSSI, D, AG from " + TABLE_SSIDInf
					+ " where APID = " + APID + " AND " + key1 + " AND " + key2
					+ " AND D >= " + dminIn + " AND D <= " + dminOut
					+ " ORDER By AG";
			c5 = db.rawQuery(query5, null);
			del = Math.abs(agminOut - agmaxIn);
		} else if ((agminIn >= agminOut) & (agmaxIn >= agmaxOut)) {
			String key1 = "AG >= " + agminOut;
			String key2 = "AG <= " + agminIn;
			String query5 = "select x, y, RSSI, D, AG from " + TABLE_SSIDInf
					+ " where APID = " + APID + " AND " + key1 + " AND " + key2
					+ " AND D >= " + dminIn + " AND D <= " + dminOut
					+ " ORDER By AG";
			c5 = db.rawQuery(query5, null);
			del = Math.abs(agminIn - agmaxOut);
		}
		c5.moveToFirst();
		int temp = c5.getCount();
		if(temp != 0)
		{
			for (c5.moveToFirst(); !c5.isLast(); c5.moveToNext()) {
				if (xy(c5.getInt(0), c5.getInt(1), xminOut, yminOut, xmaxOut, ymaxOut) == 1) {
					float Dtemp = c5.getInt(3);
					do {
						for (AGGen = agminIn; AGGen <= agminIn + del; AGGen++) {
							DGen = c5.getInt(3) + 1;
							do {
								if (DGen <= dminOut) {
									RSSIGen = (float) (RSSI0 - 10 * n* Math.log(DGen / D0)/(dminOut - dminIn));
								} else
									RSSIGen = (float) (RSSI0 - 10 * n* Math.log(DGen / D0) + error);
								level = LevelRSSI(RSSIGen);
								// Update dữ liệu vừa tinh lai vao bảng
								// TABLE_SSIDInf tai vi tri x, y d
								ContentValues vl = new ContentValues();
								vl.put("RSSI", RSSIGen);
								vl.put("PowLevel", level);
								vl.put("TypeObs", k);
								String where = "x = " + c5.getInt(0) + "and y ="
										+ c5.getInt(1);
								db.update(TABLE_SSIDInf, vl, where, null);
								DGen = DGen++;
							} while (RSSIGen > limit);
							c5.moveToNext();
						}
					} while (Dtemp <= c5.getInt(3));

				}
			}
		}
		else{ Log.d("get count", temp + "");}
		db.close();
	}
	
	// -----------------------------------------------------------------------------
	// Cac ham tuong tac co so du lieu voi bang TABLE_SSIDInf
	public void addPointvalue(int APID, float x, float y, float D, float AG, int RSSI, int PowLevel, float BW, int BandLevel) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("APID", APID);
		value.put("x", x);
		value.put("y", y);
		value.put("D", D);
		value.put("AG", AG);
		value.put("RSSI", RSSI);
		value.put("PowLevel", PowLevel);
		value.put("BW", BW);
		value.put("BandLevel", BandLevel);
		db.insert(TABLE_SSIDInf, null, value);
		db.close();
	}

	public void updatePointvalue(int PID, float RSSI, int PowLevel) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("RSSI", RSSI);
		value.put("PowLevel", PowLevel);
		String where = "ID = " + PID;
		db.update(TABLE_SSIDInf, value, where, null);
		db.close();
	}

	// ----------------------------------------------------------------------------
	// Cac ham tuong tac co so du lieu voi bang TABLE_APLevel
	public void addAPScanLevel(int APID, float x, float y, int Level) {
		SQLiteDatabase db = this.getWritableDatabase();
		ContentValues value = new ContentValues();
		value.put("APID", APID);
		value.put("x", x);
		value.put("y", y);
		value.put("Level", Level);
		db.insert(TABLE_APLevel, null, value);
		db.close();
	}


	public float[] getPoint2(int APID, int lv) {
		SQLiteDatabase db = this.getReadableDatabase();
		String query = "select x, y from" + TABLE_APLevel + " where APID = "
				+ APID + " AND Level = " + lv + "";
		Cursor c = db.rawQuery(query, null);
		float[] result = null;
		result = new float[2 * c.getCount()];
		c.moveToFirst();
		for (int i = 0; i < c.getCount(); i++) {
			float x = Float.parseFloat(c.getString(0));
			float y = Float.parseFloat(c.getString(1));
			result[2 * i] = x;
			result[2 * i + 1] = y;
			c.moveToNext();
		}
		return result;
	}
	
	// Bảng chứa giá trị biên RSSI theo một mức màu
		public void Level(int APID) {
			SQLiteDatabase db = this.getReadableDatabase();
			// Các cột giá trị của các bảng sẽ lấy
			// cv = db.rawQuery("select x, y, AG, D from "
			// + TABLE_SSIDInf + " where APID = " + APID + " and Level = " + i +
			// " ORDER By AG", null);
			
			HashMap<String, String> agArray = new HashMap<String,String>();
			HashMap<String, String> maxDArray = new HashMap<String,String>();
			Cursor cv, cvAG, cvD;
			for (int lv = 1; lv <= 15; lv++) {
				cv = db.rawQuery("select AG from " + TABLE_SSIDInf
						+ " where APID = " + APID + " and PowLevel = " + lv
						+ " ORDER By AG", null);
				int i=0;
				cv.moveToFirst();
				if (cv.getCount() != 0) {
					do{
						agArray.put( lv + "", cv.getString(0)) ;
						i++;
					}while(cv.moveToNext());
				}
//				cv.close();
			}
			
			if ( agArray.size()!= 0 && agArray != null){
				for (int kAG = 0; kAG < agArray.size(); kAG++){
					for ( int lv =1; lv <=15; lv++ ){
					float AG = Float.parseFloat( agArray.get(lv) );
					cvAG = db.rawQuery("select MAX(D) from "
							+ TABLE_SSIDInf + " where APID = " + APID
							+ " and PowLevel = " + lv + " AND AG = " + AG + "",
							null);
					cvAG.moveToFirst();
						if ( cvAG.getCount()!= 0 ){
		//					float D = Float.parseFloat(cvAG.getString(0));
							do{
								maxDArray.put( kAG + "", cvAG.getString(0));
							}while(cvAG.moveToNext());
						}
//					cvAG.close();
					}
				}
			}
			
			if ( agArray.size()!= 0 && agArray != null && maxDArray.size() != 0 && maxDArray != null ){
				for ( int maxD = 1 ; maxD < maxDArray.size(); maxD ++)
					for ( int kAG=0;kAG < agArray.size(); kAG ++)
						for ( int lv=1; lv<=15; lv++){
							cvD = db.rawQuery("select x, y from "
									+ TABLE_SSIDInf + " where APID = " + APID
									+ " and PowLevel = " + lv + " AND AG = " + kAG
									+ " AND D = " + maxD, null);
							cvD.moveToFirst();
							if (cvD.getCount() != 0) {
								do{
									for (int item = 0; item < cvD.getCount(); item++) {
										float x = Float.parseFloat(cvD.getString(0));
										float y = Float.parseFloat(cvD.getString(1));
										this.addAPScanLevel(APID, x, y, lv);
									}
								}while(cvD.moveToNext());
										
							}
//							cvD.close();
						}
			}
					
		
//				cv.close();
		
			
		}

	// ---------------------------------------------------------------------------
	// Cac ham tuong tac co so du lieu voi bang TABLE_PolyOptions

	public void createPolygonIndex() {
		SQLiteDatabase db = this.getWritableDatabase();
		String IndexPolygon[] = { "#c11b17", "#ff0000", "#f88017", "#fdd017",
				"#ffff00", "#4aa02c", "#00ff00", "#153e7e", "#56a5ec",
				"#7d1b7e", "#b93b8f", "#f778a1", "#736f6e", "#cfecec",
				"#faf8cc" };
		String color;
		int index = 15, level = 1;
		int i;
		for (i = 0; i <= IndexPolygon.length; i++) {
			color = IndexPolygon[i];
			index = index - i;
			level = level + i;
			ContentValues value = new ContentValues();
			value.put("Color", color);
			value.put("zIndex", index);
			value.put("Level", level);
			db.insert(TABLE_PolyOptions, null, value);
		}

		db.close();
	}
	
	// ----------------------------------------------------------------------------
	
	// Xoa bot cac vi tri thua trong bang
	public void deleteInfor(int id) {
		SQLiteDatabase db = this.getWritableDatabase();
		db.delete(TABLE_SSIDInf, "ID" + "=?",
				new String[] { String.valueOf(id) });
		db.close();
	}
	
	public void deleteAll() {
		SQLiteDatabase db = this.getWritableDatabase();
		db.delete(TABLE_SSIDInf, null, null);
		db.close();
	}
	//---------------------------------------------------------------------------------
	//THUAT TOAN MOI - TACH CAC GIA TRI BIEN THEO TUNG LEVEL 
	// Loc cac tap diem chua ranh gioi vat can thành một mảng
		public List<Obstacle> getObstacle(int APID) {			
			List<Obstacle> listObstacle = new ArrayList<Obstacle>();
			Obstacle point = null;
			Point p= null;
			
			
				SQLiteDatabase db = this.getReadableDatabase();
				// Lọc từng tập điểm đường bao của từng Obstacle 
				int numObstacle = numObs(APID); 
				
				for (int i =1; i<=numObstacle; i++){
					String query1 = "select x, y from" + TABLE_SSIDCollect + " where APID = "
							+ APID + " AND TypeObs = " + i + " AND InsideObs !=0"  +" ORDER By TypeObs";
					Cursor c1 = db.rawQuery(query1, null);
					p.x = c1.getColumnIndex("x");
					p.y = c1.getColumnIndex("y");
					point.points.add(p);	
					String query2 = "select x, y from" + TABLE_SSIDCollect + " where APID = "
							+ APID + " AND TypeObs = " + i + " AND OutsideObs !=0"  +" ORDER By TypeObs";
					Cursor c2 = db.rawQuery(query1, null);
					p.x = c2.getColumnIndex("x");
					p.y = c2.getColumnIndex("y");
					point.points.add(p);	
					listObstacle.add(point);
				}								
				return listObstacle;
			}
		// Xet cac diem co nam trong vat chan hay khong
					            
		public boolean  checkInPolygon(Point p, List<Point> obstacle)
	        {
	            int crossings = 0;
	            float x1, x2;
	            int n = obstacle.size();
	            for (int i = 0; i < n; i++)
	            {
	                if (p.x == obstacle.get(i).x && p.y == obstacle.get(i).y)
	                    return true;
	                /* This is done to ensure that we get the same result when
	           the line goes from left to right and right to left */
	                else if (obstacle.get(i).x < obstacle.get((i + 1) % n).x)
	                {
	                    x1 = obstacle.get(i).x;
	                    x2 = obstacle.get((i + 1) % n).x;
	                }
	                else
	                {
	                    x1 = obstacle.get((i + 1) % n).x;
	                    x2 = obstacle.get(i).x;
	                }

	                /* First check if the ray is possible to cross the line */
	                if ( p.x > x1 && p.x <= x2 && ( p.y < obstacle.get(i).y || p.y <= obstacle.get((i+1)%n).y ) )
	                {
	                    float eps = 0.000001f;
	 
	                    /* Calculate the equation of the line */
	                    float dx = obstacle.get((i+1)%n).x - obstacle.get(i).x;
	                    float dy = obstacle.get((i+1)%n).y - obstacle.get(i).y;
	                    float k;
	 
	                    // ABS dx
	                    if ( Math.abs(dx) < eps ){
	                        k = 99999999999f;//INFINITY  
	                    } else {
	                            k = dy/dx;
	                    }

	                    float m = obstacle.get(i).y - k * obstacle.get(i).x;
	               
	                    /* Find if the ray crosses the line */
	                    float y2 = k * p.x + m;
	                    if ( p.y <= y2 ){
	                            crossings++;
	                    }
	                }
	            }
	            if (crossings % 2 == 1)
	                return true;

	            return false;
	        }
		
		
	public void RSSI(int APID) {
		SQLiteDatabase db = this.getReadableDatabase();
		Point point1 = null, point2 = null;
		// Lay toa do cua AP		
		String[] p = this.getAPpos(APID);		
		float xtemp = Float.parseFloat(p[0]);
		float ytemp = Float.parseFloat(p[1]);
		point1.x = xtemp;
		point1.y = ytemp;
		// he so suy hao + phuong sai tai nhung diem thuoc LOS
		float n = n(APID);
		float error = StandDiv(APID);
		// he so suy hao + phuong sai tai nhung diem thuoc NLOS sau cac vat chan
		int i, k;
		
		List<Float> listN, listError, listSizeObstacle = new ArrayList<Float>();	
		
		for (i=1; i<=numObs(APID);i++ ){
			float nObs = nObs(APID, i);
			listN.add(new Float(nObs));// tập các hệ số suy hao tương ứng với từng vật cản
			float error2 = StandDivNlos(APID, i);
			listError.add(new Float(error2));// tập các sai số nội suy tương ứng với từng hệ số suy hao
			// kích thước vật cản 			
			float size = DMaxObs(APID, i);
			listSizeObstacle.add(new Float(size));// tập kích thước vật cản tương ứng với từng hệ số suy hao
		}
		
		int limit = -92;// giới hạn ngưỡng thu của thiết bị còn tìm thấy sóng
		
		
		String query = "select D, RSSI  from " + TABLE_SSIDCollect
				+ " where APID = " + APID + " ORDER By D";
		Cursor c = db.rawQuery(query, null);
		// lấy chỉ số tín hiệu RSSI0 tại khoảng đo đầu tiên
		float RSSI0 = 0f;
		float D0 = 0f;				
		c.moveToFirst();
		D0 = Float.parseFloat(c.getString(0));
		RSSI0 = Float.parseFloat(c.getString(1));
		
		float DGen = 0f;// khoang cach do tai vi tri D noi suy
		float RSSIGen = 0f;// chỉ số RSSI se noi suy tại vi tri D
		int AGGen = 0; // Góc của điểm noi suy so với trục toạ độ đecac
		float x = 0f;
		float y = 0f;			
		int level, leveltemp;
		Point pt;	
		float log ;
		double log2 ;
		float v2 ;
		List<Obstacle> obstacletemp = new ArrayList<Obstacle>();
		
			c.moveToNext();
			float nTemp, errorTemp, sizeObstacleTemp; 
			int i1 = 0; 
			List<Obstacle> listObstacleTemp = getObstacle(APID);
			Obstacle listPoint;
			
			DGen = D0;// gan ban kinh cua cac diem dau tien tu vi tri cua D0
			for (AGGen = 0; AGGen < 360; AGGen++) {// cho goc xoay quanh AP
				Log.d("first_loop", AGGen + "");
				do {
					DGen = DGen + 1;// tăng dần khoảng cách từ điểm đo đến AP
					// Xac dinh toa do cho diem co khoang cach noi suy
					x = (float) (DGen * Math.cos(AGGen) * 180 / Math.PI);
					y = (float) (DGen * Math.sin(AGGen) * 180 / Math.PI);
					// Doi he truc toa do
					xtemp = xtemp + x;
					ytemp = ytemp + y;
					pt.x = xtemp;
					pt.y = ytemp;
					// kiểm tra x, y có nằm trong phạm vi của vật chằn hay không?
					for (int count=1; count <=listObstacleTemp.size(); count ++){	
						listPoint = listObstacleTemp.get(count);
						if(checkInPolygon(pt, listPoint) = false){
								// Ứng với mỗi góc, tại bán kính D có được giá trị tín hiệu nội suy
								log = (float) Math.log(DGen / D0);
								log2 = Math.log(DGen / D0);
								v2 = 10 * n * log;
								RSSIGen = (float) (RSSI0 - v2) + error;
								level = LevelRSSI(RSSIGen);
								leveltemp = level;
						}else {
								// Lấy vị trí của listObstacle mà tìm thấy điểm đó 
								log = (float) Math.log(DGen / D0);
								log2 = Math.log(DGen / D0);
								v2 = 10 * listN.get(i) * log;
								RSSIGen = (float) (RSSI0 - v2) + listError.get(i);
								level = LevelRSSI(RSSIGen);
								leveltemp = level;
								}		
												
						if (level != leveltemp){
							// Chèn dữ liệu vừa nội suy vao bảng TABLE_SSIDInf
							ContentValues vl = new ContentValues();
							vl.put("APID", APID);
							vl.put("D", DGen);
							vl.put("AG", AGGen);
							vl.put("RSSI", RSSIGen);
							vl.put("x", xtemp);
							vl.put("y", ytemp);
							vl.put("PowLevel", level);
							vl.put("TypeObs", 0);
							vl.put("BW", 0);
							DGen += 1;
							db.insert(TABLE_SSIDInf, null, vl);
							
							Log.d("order", (i1 = i1 + 1) + "");
							Log.d("Dgen/D0_" + i1, DGen / D0 + "");
							Log.d("Log_" + i1, log + "");
							Log.d("Log2_" + i1, log2 + "");
							Log.d("v2_" + i1, v2 + "");
							Log.d("check", RSSIGen + ", " + limit);
							}
					}
				} while (RSSIGen > limit);
			}
			db.close();
}

	/////////////////////////////////////////////
	public float outside(Point p1, Point p2, Point p3) {			
		return(p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y);
	}
	public boolean PointInTriangle1(Point pt, Point p1, Point p2, Point p3)
		{
		boolean b1, b2, b3;

		  b1 = outside(pt, p1, p2) < 0.0f;
		  b2 = outside(pt, p2, p3) < 0.0f;
		  b3 = outside(pt, p3, p1) < 0.0f;

		  return ((b1 == b2) && (b2 == b3));
	}	
}
